#include <stdlib.h>
#include <stdio.h>
//#include <iostream.h>
//#include <iomanip.h>
#include <math.h>

const long MAX_TIME             = 10000L;
const long NO_STATIONS          = 100L;
const long FRAME_LENGTH         = 100L;
      long medium_occupied_till = -1;
      long survival_timer       = -1;
      long successful_packets   = 0;
      long no_frames            = MAX_TIME / FRAME_LENGTH;

class Station
{
public:
  void Init() {};
  void TriggerSend(long);
}; // class Station

void Station::TriggerSend(long current_time)
{
  if(current_time < medium_occupied_till) {

    // Wir senden, obwohl das Medium noch eine Zeit lang von einem
    // anderen Paket belegt ist. Das ergibt eine Kollision und toetet
    // das aktuelle Paket.

    survival_timer = -1;
  } // if

  // Das Medium war frei. Ein neues Paket ist gerade 0 Zeiteinheiten
  // alt geworden.

  else survival_timer = 0;

  // Unser neues Paket wird bis zu diesem Zeitpunkt auf dem Kanal sein:

  medium_occupied_till = current_time + FRAME_LENGTH;
} // Station::TriggerSend

main()
{
  Station* station          = new Station[NO_STATIONS];

  for(long i = 0; i < NO_STATIONS; i++)
    station[i].Init();

  // Ankunftsraten zwischen 0 und 4 Paketen pro Rahmenzeit simulieren

  for(long arrival_rate = 0; arrival_rate < 400; arrival_rate += 1) {

    // Prozentanzeige fuer gelangweilten Benutzer

    cerr << arrival_rate*100/400 << " %     " << (char)(13) << flush;

    medium_occupied_till = -1;
    survival_timer       = -1;
    successful_packets   = 0;

    // Abklappern von MAX_TIME Simulationssekunden. Ein Rahmen hat 100 davon.

    for(long time = 0; time < MAX_TIME; time++) {

      // Jede Station fragen, ob sie senden moechte

      for(long station_index = 0; station_index < NO_STATIONS; station_index++)	
      {
	// Die Station darf nur senden, wenn die Zufallszahl kleiner als arrival_rate ist,
	// aber vorsicht, sonst fragen wir viel zu oft! Es sollte eigentlich nur 1x pro
	// Rahmenzeit gefragt werden, wir fragen aber 100x pro Rahmenzeit. Das Ereignis muss
	// daher 100x (=FRAME_LENGTH) unwahrscheinlicher sein, daher arrival_rate*FRAME_LENGTH.
	// Ausserdem fragen wir jede Station einzeln, wollten aber nur eine gesamt Ankunftsrate
	// vorgeben, daher arrival_rate*FRAME_LENGTH*NO_STATIONS.

	if((abs(rand()) % (100*NO_STATIONS*FRAME_LENGTH)) < arrival_rate)
	  station[station_index].TriggerSend(time);
      } // if

      // Ein survival_timer > -1 zeigt, dass noch keine Kollision stattgefunden hat.
      // Wir inkrementieren den Timer um 1 und wuenschen dem Paket weiter alles Gute.

      if(survival_timer != -1) survival_timer++;
      if(survival_timer == FRAME_LENGTH) {

	// Der seltene Fall ist eingetreten, dass das Paket eine volle Rahmenzeit
	// ueberlebt hat.

	successful_packets++;
	survival_timer = -1;
      } // if
    } // for

    double overall_arrival_rate = ((double)arrival_rate)/100.0;

    cout << overall_arrival_rate << " " << (double)successful_packets/(double)no_frames << endl; 
  } // for

  delete[] station;
} // main
